/*
    生产者消费者模型
*/

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<semaphore.h>

//创建一个互斥量,解决数据同步问题
pthread_mutex_t mutex;
//创建两个信号量
sem_t psem;
sem_t csem;

//生产者——消费者队列，里面存放节点表示任务
struct Node
{
    int num;
    struct Node* next;
};

struct Node* head = NULL;

void* producer(void* arg){
    //不断地创建新节点，添加到链表中
    while(1){
        sem_wait(&psem);       //wait一次，信号灯就减一，wait8次即不能生产了
        //加锁
        pthread_mutex_lock(&mutex);
        struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
        //采用头插法
        newNode->next = head;
        head = newNode;
        newNode->num = rand()%100;
        printf("add node, num : %d, tid: %ld\n", newNode->num,pthread_self());
        //解锁
        pthread_mutex_unlock(&mutex);
        sem_post(&csem);       //post一次，消费者的信号灯就加1，表示有一个可以消费了
        usleep(100);
    }
    return NULL;
}

void* customer(void* arg){
    while(1){
        sem_wait(&csem);        //一开始默认值为0，在原地等待，当大于0的时候会减1操作
        //加锁
        pthread_mutex_lock(&mutex);
        //保存头节点的指针
        struct Node* temp = head;
        head = head->next;
        printf("del node, num : %d, tid : %ld\n", temp->num, pthread_self());
        free(temp);
        //解锁
        pthread_mutex_unlock(&mutex);
        sem_post(&psem);
    }
    return NULL;
}

int main(){

    //初始化互斥量
    pthread_mutex_init(&mutex,NULL);
    //初始化信号量
    sem_init(&psem, 0, 8);      //0表示对线程操作，8表示初始有8个信号灯
    sem_init(&csem, 0, 0);


    //创建5个生产者线程，5个消费者线程
    pthread_t ptid[5], ctid[5];
    for(int i = 0; i < 5; ++i){
        pthread_create(&ptid[i],NULL,producer,NULL);
        pthread_create(&ctid[i],NULL,customer,NULL);
    } 

    //设置线程分离，主线程退出后，子线程仍可以运行
    for(int i = 0; i < 5; ++i){
        pthread_detach(ptid[i]);
        pthread_detach(ctid[i]);
    }

    while(1){
        sleep(10);         //为了确保能执行到销毁互斥量
    }

    pthread_mutex_destroy(&mutex);

    //主线程退出
    pthread_exit(NULL);

    return 0;
}

